Dynamic wakes 1¶
Spatially homogeneous wake propagation¶
For spatially homogeneous timeseries input data, foxes can compute dynamic wake propagation. This in principle works by following a flow trace backwards in time for each point of interest, and identifying it with a wake trajectory if it hits a rotor.
Since all foxes computations are based on chunks of input states, this concept only works if
either all states fall into a single chunk,
or the
Iterativealgorithm is used for the calculation.
The later is necessary in case the wake originates from a state previous to the chunk of evaluation, since the default Downwind algorithm does not allow cross-chunk communication during the calculation.
These are the inlcudes for this example:
In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["animation.html"] = "jshtml"
import foxes
import foxes.variables as FV
import foxes.constants as FC
We create a case with a regular 3 x 3 wind farm layout:
In [2]:
mbook = foxes.models.ModelBook()
states = foxes.input.states.Timeseries(
data_source="timeseries_100.csv.gz",
output_vars=[FV.WS, FV.WD, FV.TI, FV.RHO],
var2col={FV.WS: "ws", FV.WD: "wd", FV.TI: "ti"},
fixed_vars={FV.RHO: 1.225, FV.TI: 0.07},
)
farm = foxes.WindFarm()
foxes.input.farm_layout.add_grid(
farm,
xy_base=np.array([0.0, 0.0]),
step_vectors=np.array([[1000.0, 0], [0, 800.0]]),
steps=(3, 3),
turbine_models=["DTU10MW"],
verbosity=0
)
algo = foxes.algorithms.Iterative(
mbook,
farm,
states=states,
rotor_model="centre",
wake_models=["Bastankhah2014_linear_k004"],
wake_frame="timelines",
partial_wakes_model="auto",
chunks={FC.STATE: 500, FC.POINT: 5000},
verbosity=1
)
Notice the wake frame choice timelines, which is a pre-defined instance of the class Timelines from the model book.
Let’s run the wind farm calculation:
In [3]:
with foxes.utils.runners.DaskRunner() as runner:
farm_results = runner.run(algo.calc_farm)
Algorithm Iterative: Iteration 0
Initializing algorithm 'Iterative'
Initializing model 'Iterative'
Initializing model 'Timeseries'
States 'Timeseries': Reading static data 'timeseries_100.csv.gz' from context 'states'
Path: /home/jonas/gits/wakes/foxes/foxes/data/states/timeseries_100.csv.gz
Initializing model 'centre'
Initializing model 'basic_ctrl_prer'
Initializing model 'DTU10MW'
Turbine type 'DTU10MW': Reading static data from context 'power_ct_curve'
Path: /home/jonas/gits/wakes/foxes/foxes/data/power_ct_curves/DTU-10MW-D178d3-H119.csv
Initializing model 'basic_ctrl_postr'
Initializing model 'basic_ctrl'
Initializing model 'timelines'
timelines: Pre-calculating ambient wind vectors
Partial wakes 'auto': Applying PartialAxiwake to ['Bastankhah2014_linear_k004']
Initializing model 'ws_linear'
Initializing model 'Bastankhah2014_linear_k004'
Initializing model 'PartialAxiwake10'
Initializing model 'auto'
--------------------------------------------------
Running Iterative: calc_farm
--------------------------------------------------
n_states : 100
n_turbines: 9
--------------------------------------------------
states : Timeseries (Timeseries)
rotor : centre (CentreRotor)
controller: basic_ctrl (BasicFarmController)
partialwks: auto (Mapped)
wake frame: timelines (Timelines)
--------------------------------------------------
wakes:
0) Bastankhah2014_linear_k004 (Bastankhah2014)(k=0.04, sp=ws_linear)
--------------------------------------------------
turbine models:
0) DTU10MW (PCtFile)
--------------------------------------------------
Initializing model 'SetXYHD'
Initializing model 'SetXYHD_t2f'
Initializing model 'calc_yaw_CentreRotor1'
Initializing model 'CalcOrder'
Initializing model 'SetAmbFarmResults'
Initializing model 'URelax_CT'
Initializing model 'FarmWakesCalculation'
Initializing model 'Iterative_calc'
--------------------------------------------------
Model oder
--------------------------------------------------
00) SetXYHD_t2f
01) basic_ctrl
02) calc_yaw_CentreRotor1
03) centre
04) CalcOrder
05) basic_ctrl
05.0) Post-rotor: DTU10MW
06) SetAmbFarmResults
07) FarmWakesCalculation
--------------------------------------------------
[########################################] | 100% Completed | 102.13 ms
Input data:
<xarray.Dataset>
Dimensions: (state: 100, turbine: 9, Timeseries_vars: 2, tmodels: 1)
Coordinates:
* state (state) datetime64[ns] 2023-07-07T12:00:00 ... 2023-07-0...
* Timeseries_vars (Timeseries_vars) <U2 'WS' 'WD'
* tmodels (tmodels) <U7 'DTU10MW'
Dimensions without coordinates: turbine
Data variables:
weight (state, turbine) float64 dask.array<chunksize=(100, 9), meta=np.ndarray>
Timeseries_data (state, Timeseries_vars) float64 dask.array<chunksize=(100, 2), meta=np.ndarray>
tmodel_sels (state, turbine, tmodels) bool dask.array<chunksize=(100, 9, 1), meta=np.ndarray>
Output farm variables: AMB_CT, AMB_P, AMB_REWS, AMB_REWS2, AMB_REWS3, AMB_RHO, AMB_TI, AMB_WD, AMB_YAW, CT, D, H, P, REWS, REWS2, REWS3, RHO, TI, WD, X, Y, YAW, order, weight
Chunks: {'state': 500, 'point': 5000}
Calculating 100 states for 9 turbines
[########################################] | 100% Completed | 102.74 ms
Algorithm Iterative: Iteration 1
[########################################] | 100% Completed | 101.17 ms
[########################################] | 100% Completed | 102.10 ms
DefaultConv: Convergence check
REWS: delta = 2.433e-01, lim = 1.000e-05 -- FAILED
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.661e-03, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 2
[########################################] | 100% Completed | 101.79 ms
[########################################] | 100% Completed | 101.84 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 8.307e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 3
[########################################] | 100% Completed | 101.47 ms
[########################################] | 100% Completed | 101.78 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 4.154e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 4
[########################################] | 100% Completed | 101.01 ms
[########################################] | 100% Completed | 101.66 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 2.077e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 5
[########################################] | 100% Completed | 132.89 ms
[########################################] | 100% Completed | 101.69 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.038e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 6
[########################################] | 100% Completed | 101.52 ms
[########################################] | 100% Completed | 101.72 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 5.192e-05, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 7
[########################################] | 100% Completed | 101.28 ms
[########################################] | 100% Completed | 102.87 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 2.596e-05, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 8
[########################################] | 100% Completed | 101.50 ms
[########################################] | 100% Completed | 101.46 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.298e-05, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 9
[########################################] | 100% Completed | 101.30 ms
[########################################] | 100% Completed | 204.60 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 6.490e-06, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 10
[########################################] | 100% Completed | 101.83 ms
[########################################] | 100% Completed | 104.19 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 3.245e-06, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 11
[########################################] | 100% Completed | 101.67 ms
[########################################] | 100% Completed | 100.94 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.622e-06, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 12
[########################################] | 100% Completed | 101.36 ms
[########################################] | 100% Completed | 104.16 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 8.112e-07, lim = 1.000e-06 -- OK
Algorithm Iterative: Convergence reached.
Notice the iterations and the convergence behaviour. Now the farm results are ready:
In [4]:
farm_df = farm_results.to_dataframe()
print("\nFarm results data:\n")
print(farm_df[[FV.AMB_REWS, FV.REWS, FV.P]])
Farm results data:
AMB_REWS REWS P
state turbine
2023-07-07 12:00:00 0 6.0 6.000000 1532.700000
1 6.0 6.000000 1532.700000
2 6.0 6.000000 1532.700000
3 6.0 4.836878 714.456232
4 6.0 4.836878 714.456232
... ... ... ...
2023-07-07 13:39:00 4 6.0 4.836878 714.456232
5 6.0 4.836878 714.456232
6 6.0 4.492870 535.950095
7 6.0 4.492870 535.950095
8 6.0 4.492870 535.950095
[900 rows x 3 columns]
This timeseries has a time step of 1 minute. Let’s visualize the wake dynamics in am animation:
In [5]:
with foxes.utils.runners.DaskRunner() as runner:
fig, axs = plt.subplots(2, 1, figsize=(5.2,7),
gridspec_kw={'height_ratios': [3, 1]})
anim = foxes.output.Animator(fig)
# this adds the flow anomation to the upper panel:
of = foxes.output.FlowPlots2D(algo, farm_results, runner=runner)
anim.add_generator(
of.gen_states_fig_xy(
FV.WS,
resolution=30,
quiver_pars=dict(angles="xy", scale_units="xy", scale=0.013),
quiver_n=35,
xmax=5000,
ymax=5000,
fig=fig,
ax=axs[0],
ret_im=True,
title=None,
animated=True,
)
)
# This adds the REWS signal animation to the lower panel:
o = foxes.output.FarmResultsEval(farm_results)
anim.add_generator(
o.gen_stdata(
turbines=[4, 7],
variable=FV.REWS,
fig=fig,
ax=axs[1],
ret_im=True,
legloc="upper left",
animated=True,
)
)
ani = anim.animate()
plt.close()
print("done.")
print("Creating animation")
ani
Creating animation data
done.
Creating animation
Out[5]:
For the fun of it, let’s re-run this case assuming the time step was 10 s instead of 1 min. We can do so by using the wake frame Timelines(dt_min=1/6), which is called timelines_10s in the model book:
In [6]:
algo.finalize(clear_mem=True)
algo = foxes.algorithms.Iterative(
mbook,
farm,
states=states,
rotor_model="centre",
wake_models=["Bastankhah2014_linear_k004"],
wake_frame="timelines_10s",
partial_wakes_model="auto",
chunks={FC.STATE: 500, FC.POINT: 5000},
verbosity=1
)
with foxes.utils.runners.DaskRunner() as runner:
farm_results = runner.run(algo.calc_farm)
fig, axs = plt.subplots(2, 1, figsize=(5.2,7),
gridspec_kw={'height_ratios': [3, 1]})
anim = foxes.output.Animator(fig)
# this adds the flow anomation to the upper panel:
of = foxes.output.FlowPlots2D(algo, farm_results, runner=runner)
anim.add_generator(
of.gen_states_fig_xy(
FV.WS,
resolution=30,
quiver_pars=dict(angles="xy", scale_units="xy", scale=0.013),
quiver_n=35,
xmax=5000,
ymax=5000,
fig=fig,
ax=axs[0],
ret_im=True,
title=None,
animated=True,
)
)
# This adds the REWS signal animation to the lower panel:
o = foxes.output.FarmResultsEval(farm_results)
anim.add_generator(
o.gen_stdata(
turbines=[4, 7],
variable=FV.REWS,
fig=fig,
ax=axs[1],
ret_im=True,
legloc="upper left",
animated=True,
)
)
ani = anim.animate()
plt.close()
print("done.")
print("Creating animation")
ani
Algorithm Iterative: Iteration 0
Initializing algorithm 'Iterative'
Initializing model 'Iterative'
Initializing model 'Timeseries'
States 'Timeseries': Reading file /home/jonas/gits/wakes/foxes/foxes/data/states/timeseries_100.csv.gz
Initializing model 'centre'
Initializing model 'basic_ctrl_prer'
Initializing model 'DTU10MW'
Turbine type 'DTU10MW': Reading static data from context 'power_ct_curve'
Path: /home/jonas/gits/wakes/foxes/foxes/data/power_ct_curves/DTU-10MW-D178d3-H119.csv
Initializing model 'basic_ctrl_postr'
Initializing model 'basic_ctrl'
Initializing model 'timelines_10s'
timelines_10s: Pre-calculating ambient wind vectors
Partial wakes 'auto': Applying PartialAxiwake to ['Bastankhah2014_linear_k004']
Initializing model 'ws_linear'
Initializing model 'Bastankhah2014_linear_k004'
Initializing model 'PartialAxiwake12'
Initializing model 'auto'
--------------------------------------------------
Running Iterative: calc_farm
--------------------------------------------------
n_states : 100
n_turbines: 9
--------------------------------------------------
states : Timeseries (Timeseries)
rotor : centre (CentreRotor)
controller: basic_ctrl (BasicFarmController)
partialwks: auto (Mapped)
wake frame: timelines_10s (Timelines)
--------------------------------------------------
wakes:
0) Bastankhah2014_linear_k004 (Bastankhah2014)(k=0.04, sp=ws_linear)
--------------------------------------------------
turbine models:
0) DTU10MW (PCtFile)
--------------------------------------------------
Initializing model 'SetXYHD1'
Initializing model 'SetXYHD1_t2f'
Initializing model 'calc_yaw_CentreRotor2'
Initializing model 'CalcOrder1'
Initializing model 'SetAmbFarmResults1'
Initializing model 'URelax13_CT'
Initializing model 'FarmWakesCalculation13'
Initializing model 'Iterative_calc'
--------------------------------------------------
Model oder
--------------------------------------------------
00) SetXYHD1_t2f
01) basic_ctrl
02) calc_yaw_CentreRotor2
03) centre
04) CalcOrder1
05) basic_ctrl
05.0) Post-rotor: DTU10MW
06) SetAmbFarmResults1
07) FarmWakesCalculation13
--------------------------------------------------
[########################################] | 100% Completed | 101.48 ms
Input data:
<xarray.Dataset>
Dimensions: (state: 100, turbine: 9, Timeseries_vars: 2, tmodels: 1)
Coordinates:
* state (state) datetime64[ns] 2023-07-07T12:00:00 ... 2023-07-0...
* Timeseries_vars (Timeseries_vars) <U2 'WS' 'WD'
* tmodels (tmodels) <U7 'DTU10MW'
Dimensions without coordinates: turbine
Data variables:
weight (state, turbine) float64 dask.array<chunksize=(100, 9), meta=np.ndarray>
Timeseries_data (state, Timeseries_vars) float64 dask.array<chunksize=(100, 2), meta=np.ndarray>
tmodel_sels (state, turbine, tmodels) bool dask.array<chunksize=(100, 9, 1), meta=np.ndarray>
Output farm variables: AMB_CT, AMB_P, AMB_REWS, AMB_REWS2, AMB_REWS3, AMB_RHO, AMB_TI, AMB_WD, AMB_YAW, CT, D, H, P, REWS, REWS2, REWS3, RHO, TI, WD, X, Y, YAW, order, weight
Chunks: {'state': 500, 'point': 5000}
Calculating 100 states for 9 turbines
[########################################] | 100% Completed | 203.33 ms
Algorithm Iterative: Iteration 1
[########################################] | 100% Completed | 102.67 ms
[########################################] | 100% Completed | 104.58 ms
DefaultConv: Convergence check
REWS: delta = 2.433e-01, lim = 1.000e-05 -- FAILED
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.661e-03, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 2
[########################################] | 100% Completed | 101.77 ms
[########################################] | 100% Completed | 101.63 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 8.307e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 3
[########################################] | 100% Completed | 102.20 ms
[########################################] | 100% Completed | 102.82 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 4.154e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 4
[########################################] | 100% Completed | 101.94 ms
[########################################] | 100% Completed | 103.38 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 2.077e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 5
[########################################] | 100% Completed | 102.61 ms
[########################################] | 100% Completed | 101.96 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.038e-04, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 6
[########################################] | 100% Completed | 101.14 ms
[########################################] | 100% Completed | 102.85 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 5.192e-05, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 7
[########################################] | 100% Completed | 101.45 ms
[########################################] | 100% Completed | 101.71 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 2.596e-05, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 8
[########################################] | 100% Completed | 101.41 ms
[########################################] | 100% Completed | 102.35 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.298e-05, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 9
[########################################] | 100% Completed | 101.47 ms
[########################################] | 100% Completed | 104.90 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 6.490e-06, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 10
[########################################] | 100% Completed | 101.97 ms
[########################################] | 100% Completed | 102.24 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 3.245e-06, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 11
[########################################] | 100% Completed | 102.11 ms
[########################################] | 100% Completed | 102.64 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 1.622e-06, lim = 1.000e-06 -- FAILED
Algorithm Iterative: Iteration 12
[########################################] | 100% Completed | 102.02 ms
[########################################] | 100% Completed | 102.46 ms
DefaultConv: Convergence check
REWS: delta = 0.000e+00, lim = 1.000e-05 -- OK
TI : delta = 0.000e+00, lim = 1.000e-06 -- OK
CT : delta = 8.112e-07, lim = 1.000e-06 -- OK
Algorithm Iterative: Convergence reached.
Creating animation data
done.
Creating animation
Out[6]: